///////////////////////////////////////////////////////////////////////////////
//-----------------------------------------------------------------------------
#ifndef GLSLPROGRAM_H_
#define GLSLPROGRAM_H_

#include <Config.h>
#include <Shader/GPUProgram.h>
#include <string>
#include <map>
#include <vector>

//-----------------------------------------------------------------------------

typedef	struct _struct_shader_var_glsl_glsl_
{
	u8		func;
	GLboolean	attrib;
	GLint	loc;
	union
	{
		GLfloat	vFloat[4];
		GLint	vInt[4];
	}	value;

	_struct_shader_var_glsl_glsl_(u8 f, GLboolean a, GLint l, GLfloat v)
	{
		func = f;
		attrib = a;
		loc = l;
		value.vFloat[0] = v;
	}

	_struct_shader_var_glsl_glsl_(u8 f, GLboolean a, GLint l, GLfloat *v, u8 size)
	{
		func = f;
		attrib = a;
		loc = l;
		memcpy( value.vFloat, v, sizeof( GLfloat ) * size );
	}

	_struct_shader_var_glsl_glsl_(u8 f, GLboolean a, GLint l, GLint v)
	{
		func = f;
		attrib = a;
		loc = l;
		value.vInt[0] = v;
	}

	_struct_shader_var_glsl_glsl_(u8 f, GLboolean a, GLint l, GLint *v, u8 size)
	{
		func = f;
		attrib = a;
		loc = l;
		memcpy( value.vInt, v, sizeof( GLint ) * size );
	}

}	_shader_var_glsl_;

/**
* Implementeaza folosind GLSL GPUProgram
*/
class GLSLProgram : public GPUProgram
{
private:
	/**
	* Vertex shader(program)
	*/
	GLenum m_glslVertexShader;
	
	/**
	* Fragment shader(program)
	*/
	GLenum m_glslFragmentShader;
	
	/**
	* Obiectul program ce contine atat fragment shaderul cat si vertex shaderul
	*/
	GLenum m_glslCombinedShader;

	struct Param
	{
		GLboolean	isAttirb;
		GLint	location;
		GLenum	type;
		GLint	size;
		
		operator bool()
		{
			return location > -1;
		}
	};
	/**
	* Map pentru pastrarea parametrilor programului Cg
	*/
	//map<string, GLint> m_glslAtribMap;
	//map<string, GLint> m_glslUniformMap;
	//int m_noAttrib;
	//int m_noUniform;
	std::map<std::string, Param> m_glslParametersMap;

	/**
	*	Shader vars
	*/
	std::vector<_shader_var_glsl_>	m_glslShaderVarSaves;
	void		processSavedVars();

public:
	/**
	* Constructor fara parametri; se poate incarca un program cu Load()
	*/
	GLSLProgram();
	
	/**
	* Constructor ce creeaza si incarca un program Cg
	* dat prin vertex si/sau fragment shader
	*/
	GLSLProgram(File* sourceVS, File* sourceFS, const char *vertexFunc, const char *fragFunc);
	
	/**
	* Incarca parametrii programului Cg si ii pune in map-ul m_cgParametersMap
	*/
	void LoadParameters();

	/**
	*	Has parameter
	*/
	bool HasParameter(const char* paramName);
	
	/**
	* Obtinem pointerul la un parametrul dat
	*/
	Param GetParameter(const char* paramName);

	// Mostenite din GPUProgram
	bool Load(File* sourceVS, File* sourceFS, const char *vertexFunc = "", const char *fragFunc = "", const char *argsV = "", const char *argsF = "");

	bool Compile();

	bool Link();

	bool Validate();

	virtual void SetParameter1i(const char* paramName, int value);
	virtual void SetParameter2i(const char* paramName, int* value);
	virtual void SetParameter3i(const char* paramName, int* value);
	virtual void SetParameter4i(const char* paramName, int* value);

	virtual void SetParameter1f(const char* paramName, float value);
	virtual void SetParameter2f(const char* paramName, float* value);
	virtual void SetParameter3f(const char* paramName, float* value);
	virtual void SetParameter4f(const char* paramName, float* value);

	virtual void SetParameterTexture(const char* paramName, GLuint textureHandle, GLuint textureUnit);
	virtual void EnableParameterTexture(const char* paramName);

	virtual void		SetParameterMatrixf(const char* paramName, GLfloat *mat);

	void Use(bool use = true);

	void Delete();

	virtual ~GLSLProgram();
};

#endif
//-----------------------------------------------------------------------------
///////////////////////////////////////////////////////////////////////////////
